package utils

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"math"
	"os"
)

/*IsAudio
* 音频格式判断
* @param data []byte
* @return bool 音频格式是否正确
* @return string 音频格式
 */
func IsAudio(data []byte) (bool, string) {
	if IsWAV(data) {
		return true, "wav"
	}
	if IsMP3(data) {
		return true, "mp3"
	}
	if IsAAC(data) {
		return true, "aac"
	}
	if IsOPUS(data) {
		return true, "opus"
	}
	if IsPCM(data) {
		return true, "pcm"
	}
	return false, "error"
}

func IsWAV(data []byte) bool {
	if len(data) < 12 {
		return false
	}
	return bytes.Equal(data[:4], []byte("RIFF")) && bytes.Equal(data[8:12], []byte("WAVE"))
}

func IsMP3(data []byte) bool {
	if len(data) < 4 {
		return false
	}
	frameHeader := data[0] >> 3
	return frameHeader == 0x1F
}

func IsOPUS(data []byte) bool {
	if len(data) < 8 {
		return false
	}
	return bytes.Equal(data[:8], []byte("OpusHead"))
}

func IsAAC(data []byte) bool {
	if len(data) < 2 {
		return false
	}
	frameHeader := data[0] >> 3
	return frameHeader == 0x1F
}
func IsPCM(data []byte) bool {
	// 简单的能量阈值检测
	threshold := 16000
	for i := 0; i < len(data); i += 2 {
		sample := int16(data[i]) | int16(data[i+1])<<8
		if math.Abs(float64(sample)) > float64(threshold) {
			return true
		}
	}
	return false
}

// Int16sToBytesBigEndian 将 []int16 转换为 []byte，使用大端字节序
func Int16sToBytesBigEndian(data []int16) []byte {
	var buf bytes.Buffer
	for _, val := range data {
		// 使用大端字节序将 int16 写入缓冲区
		err := binary.Write(&buf, binary.BigEndian, val)
		if err != nil {
			fmt.Println("写入二进制数据时出错:", err)
			return nil
		}
	}
	return buf.Bytes()
}

// Int16sToBytesLittleEndian 将 []int16 转换为 []byte，使用小端字节序
func Int16sToBytesLittleEndian(data []int16) []byte {
	var buf bytes.Buffer
	for _, val := range data {
		// 使用小端字节序将 int16 写入缓冲区
		err := binary.Write(&buf, binary.LittleEndian, val)
		if err != nil {
			fmt.Println("写入二进制数据时出错:", err)
			return nil
		}
	}
	return buf.Bytes()
}

// PCMStream 用于管理流式 PCM 数据
type PCMStream struct {
	buffer []byte // 缓冲区，用于存储拼接后的 PCM 数据
}

// Append 数据到流中
func (p *PCMStream) Append(data []byte) {
	p.buffer = append(p.buffer, data...)
}

// GetPCMData 获取当前拼接后的 PCM 数据
func (p *PCMStream) GetPCMData() []byte {
	return p.buffer
}

// IsPCM 检测当前数据是否为 PCM 数据
func (p *PCMStream) IsPCM(threshold int16) bool {
	for i := 0; i < len(p.buffer); i += 2 {
		sample := int16(p.buffer[i]) | int16(p.buffer[i+1])<<8
		if math.Abs(float64(sample)) > float64(threshold) {
			return true
		}
	}
	return false
}

// Clear 清空缓冲区
func (p *PCMStream) Clear() {
	p.buffer = nil
}

// processAudioStream 将音频流分割成帧
func ProcessAudioStream(data []byte, bytesPerFrame int) [][]int16 {
	var frames [][]int16

	for i := 0; i < len(data); i += bytesPerFrame {
		end := i + bytesPerFrame
		if end > len(data) {
			end = len(data)
		}

		frameData := data[i:end]
		frameSamples := extractSamples(frameData)
		frames = append(frames, frameSamples)
	}

	return frames
}

// extractSamples 从字节切片中提取样本
func extractSamples(data []byte) []int16 {
	var samples []int16
	for i := 0; i < len(data); i += 2 {
		sample := int16(binary.LittleEndian.Uint16(data[i : i+2]))
		samples = append(samples, sample)
	}
	return samples
}

// SaveFramesToFile saveFramesToFile 将帧数据保存到文件
func SaveFramesToFile(filename string, frames [][]int16, sampleRate int, channels int) error {
	// 打开文件
	file, err := os.Create(filename)
	if err != nil {
		return fmt.Errorf("failed to create file: %w", err)
	}
	defer file.Close()

	// 计算总样本数
	totalSamples := 0
	for _, frame := range frames {
		totalSamples += len(frame)
	}

	// 计算数据块大小（每个样本 2 字节）
	dataSize := totalSamples * 2

	// WAV 文件头
	header := make([]byte, 44)
	copy(header[0:4], "RIFF")                                                   // RIFF
	binary.LittleEndian.PutUint32(header[4:8], 36+uint32(dataSize))             // 文件大小（不包括 RIFF 和 WAVE）
	copy(header[8:12], "WAVE")                                                  // WAVE
	copy(header[12:16], "fmt ")                                                 // fmt
	binary.LittleEndian.PutUint32(header[16:20], 16)                            // fmt 块大小
	binary.LittleEndian.PutUint16(header[20:22], 1)                             // PCM 格式
	binary.LittleEndian.PutUint16(header[22:24], uint16(channels))              // 通道数
	binary.LittleEndian.PutUint32(header[24:28], uint32(sampleRate))            // 采样率
	binary.LittleEndian.PutUint32(header[28:32], uint32(sampleRate*2*channels)) // 数据速率
	binary.LittleEndian.PutUint16(header[32:34], uint16(2*channels))            // 块对齐
	binary.LittleEndian.PutUint16(header[34:36], 16)                            // 每样本位数
	copy(header[36:40], "data")                                                 // data
	binary.LittleEndian.PutUint32(header[40:44], uint32(dataSize))              // 数据大小

	// 写入文件头
	_, err = file.Write(header)
	if err != nil {
		return fmt.Errorf("failed to write WAV header: %w", err)
	}

	// 写入音频数据
	for _, frame := range frames {
		for _, sample := range frame {
			err := binary.Write(file, binary.LittleEndian, sample)
			if err != nil {
				return fmt.Errorf("failed to write sample to file: %w", err)
			}
		}
	}

	fmt.Println("Frames saved to", filename)
	return nil
}

// SaveFramesToPCMFile 将音频帧保存为原始的 PCM 文件
func SaveFramesToPCMFile(filename string, frames [][]int16) error {
	// 打开文件
	file, err := os.Create(filename)
	if err != nil {
		return fmt.Errorf("failed to create file: %w", err)
	}
	defer file.Close()

	// 遍历所有帧，将每个样本写入文件
	for _, frame := range frames {
		for _, sample := range frame {
			err := binary.Write(file, binary.LittleEndian, sample)
			if err != nil {
				return fmt.Errorf("failed to write sample to file: %w", err)
			}
		}
	}

	fmt.Println("Frames saved to", filename)
	return nil
}
